﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Linq;
using System.Linq;
using System.Windows.Input;

using GalaSoft.MvvmLight.Command;

using Organizer.Model;

namespace Organizer.ViewModel
{
    using System;

    /// <summary>
    /// The organization view model.
    /// </summary>
    public class OrganizationViewModel : BaseViewModel
    {
        #region Fields

        /// <summary>
        /// The _edited organization (Cloned object of currently edited organization).
        /// </summary>
        private Organization _editedOrganization;

        /// <summary>
        /// The _organization to edit.
        /// </summary>
        private Organization _organizationToEdit;

        /// <summary>
        /// The status.
        /// </summary>
        private State status = State.Normal;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="OrganizationViewModel"/> class.
        /// </summary>
        public OrganizationViewModel()
        {
            NotifyPropertyChanged("Organizations");
            this.AddCommand = new RelayCommand(() => AddOrganization());
            this.EditCommand = new RelayCommand<Organization>(org => { EditOrganization(org); });
            this.SaveCommand = new RelayCommand(() => SaveOrganization());
            this.CancelCommand = new RelayCommand(() => CancelOrganization());
            this.CancelSelectionCommand = new RelayCommand(() => CancelSelection());
            this.ManageCommand = new RelayCommand(() => ManageSelection());
            this.DeleteOrganizationsCommand = new RelayCommand(() => DeleteOrganizations());
            this.RefreshCommand = new RelayCommand(() => RefreshOrganization());
            this.BackKeyPressCommand = new RelayCommand<CancelEventArgs>(e => BackKeyPressAction(e));
            Status = State.Normal;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets AddCommand.
        /// </summary>
        public ICommand AddCommand { get; set; }

        /// <summary>
        /// Gets or sets BackKeyPressCommand.
        /// </summary>
        public ICommand BackKeyPressCommand { get; set; }

        /// <summary>
        /// Gets or sets CancelCommand.
        /// </summary>
        public ICommand CancelCommand { get; set; }

        /// <summary>
        /// Gets or sets CancelSelectionCommand.
        /// </summary>
        public ICommand CancelSelectionCommand { get; set; }

        /// <summary>
        /// Gets or sets DeleteOrganizationsCommand.
        /// </summary>
        public ICommand DeleteOrganizationsCommand { get; set; }

        /// <summary>
        /// Gets or sets EditCommand.
        /// </summary>
        public ICommand EditCommand { get; set; }

        /// <summary>
        /// Gets or sets EditedOrganization.
        /// </summary>
        public Organization EditedOrganization
        {
            get
            {
                if (_editedOrganization == null)
                {
                    _editedOrganization = new Organization();
                }

                return _editedOrganization;
            }

            set
            {
                _editedOrganization = value;
                NotifyPropertyChanged(() => this.EditedOrganization);
            }
        }

        /// <summary>
        /// Gets or sets ManageCommand.
        /// </summary>
        public ICommand ManageCommand { get; set; }

        /// <summary>
        /// Gets or sets OrganizationToEdit.
        /// </summary>
        public Organization OrganizationToEdit
        {
            get
            {
                return this._organizationToEdit ?? (this._organizationToEdit = new Organization());
            }

            set
            {
                _organizationToEdit = value;
                NotifyPropertyChanged(() => this.OrganizationToEdit);
            }
        }

        /// <summary>
        /// Gets Organizations from context.
        /// </summary>
        public List<Organization> Organizations
        {
            get { return OrganizerDataContext.Instance.Organizations.Where(org => org.Id != Guid.Empty).ToList(); }
        }

        /// <summary>
        /// Gets or sets RefreshCommand.
        /// </summary>
        public ICommand RefreshCommand { get; set; }

        /// <summary>
        /// Gets or sets SaveCommand.
        /// </summary>
        public ICommand SaveCommand { get; set; }

        /// <summary>
        /// Gets or sets Status. Property to control icons in AppBar.
        /// </summary>
        public State Status
        {
            get
            {
                return status;
            }

            set
            {
                status = value;
                NotifyPropertyChanged(() => this.Status);
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Manage selection.
        /// </summary>
        public void ManageSelection()
        {
            Status = State.ManageSelection;
            NotifyPropertyChanged(() => this.Organizations);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Add organization.
        /// </summary>
        private void AddOrganization()
        {
            Status = State.Edit;
            EditedOrganization = new Organization();
            OrganizationToEdit = new Organization(); 
            NotifyPropertyChanged(() => this.Organizations);
        }

        /// <summary>
        /// The back key press action.
        /// </summary>
        /// <param name="e">
        /// The CancelEventArgs.
        /// </param>
        private void BackKeyPressAction(CancelEventArgs e)
        {
            if (Status == State.Edit)
            {
                e.Cancel = true;
                Status = State.Normal;
                EditedOrganization = null;
                NotifyPropertyChanged(() => this.Organizations);
            }

            if (Status == State.ManageSelection)
            {
                Organizations.ForEach(x =>
                {
                    if (x.IsSelectedMultiSelect)
                    {
                        x.IsSelectedMultiSelect = false;
                    }
                    NotifyPropertyChanged(string.Empty);
                });
                e.Cancel = true;
                Status = State.Normal;
                EditedOrganization = null;
                NotifyPropertyChanged(() => this.Organizations);
            }
        }

        /// <summary>
        /// Cancel organization.
        /// </summary>
        private void CancelOrganization()
        {
            Status = State.Normal;
            EditedOrganization = null;
            OrganizerDataContext.Instance.SubmitChanges();
            NotifyPropertyChanged(() => this.Organizations);
        }

        /// <summary>
        /// Cancel selection.
        /// </summary>
        private void CancelSelection()
        {
            Organizations.ForEach(x =>
                {
                    if (x.IsSelectedMultiSelect)
                    {
                        x.IsSelectedMultiSelect = false;
                    }

                    NotifyPropertyChanged(string.Empty);
                });
            NotifyPropertyChanged(() => this.Organizations);
            Status = State.Normal;
        }

        /// <summary>
        /// Delete organizations.
        /// </summary>
        private void DeleteOrganizations()
        {
            var orgs = new List<Organization>();
            Organizations.ForEach(x =>
                {
                    if (x.IsSelectedMultiSelect)
                    {
                        orgs.Add(x);
                    }
                });
            try
            {
                OrganizerDataContext.Instance.Organizations.DeleteAllOnSubmit(orgs);
                OrganizerDataContext.Instance.SubmitChanges();
            }
            catch
            {
                foreach (ObjectChangeConflict o in OrganizerDataContext.Instance.ChangeConflicts)
                {
                    o.Resolve(RefreshMode.KeepChanges);
                }

                OrganizerDataContext.Instance.SubmitChanges();
            }

            Status = State.Normal;
            NotifyPropertyChanged(() => this.Organizations);
        }

        /// <summary>
        /// Edit organization.
        /// </summary>
        /// <param name="org">
        /// The organization to edit.
        /// </param>
        private void EditOrganization(Organization org)
        {
            OrganizationToEdit = org;
            EditedOrganization = Organization.Create(org);
            Status = State.Edit;
            NotifyPropertyChanged(() => this.Organizations);
        }

        /// <summary>
        /// Refresh organization.
        /// </summary>
        private void RefreshOrganization()
        {
            NotifyPropertyChanged(() => this.Organizations);
        }

        /// <summary>
        /// Save organization.
        /// </summary>
        private void SaveOrganization()
        {
            OrganizationToEdit.Name = EditedOrganization.Name;
            OrganizationToEdit.Description = EditedOrganization.Description;

            if (!string.IsNullOrEmpty(OrganizationToEdit.Name))
            {
                if (!Organizations.Contains(OrganizationToEdit))
                {
                    OrganizerDataContext.Instance.Organizations.InsertOnSubmit(OrganizationToEdit);
                }                               
                
                OrganizerDataContext.Instance.SubmitChanges();
                Status = State.Normal;
                NotifyPropertyChanged(() => this.Organizations);
            }
        }

        #endregion
    }
}
